//
// Copyright (C) 2010 Tarmin Rehve <tarmin.rehve@gmail.com>
//
//This file is part of the LibSndFile.NET software library.
//
//    LibSndFile.NET is free software: you can redistribute it and/or modify
//    it under the terms of the GNU Lesser Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    LibSndFile.NET is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Lesser License for more details.
//
//    You should have received a copy of the GNU Lesser Public License
//    along with LibSndFile.NET.  If not, see <http://www.gnu.org/licenses/>.

#pragma once


namespace SndFileConverter {

	using namespace System;
	using namespace System::ComponentModel;
	using namespace System::Collections;
	using namespace System::Windows::Forms;
	using namespace System::Data;
	using namespace System::Drawing;
    using namespace LibSndFile;

	/// <summary>
	/// Summary for Form1
	///
	/// WARNING: If you change the name of this class, you will need to change the
	///          'Resource File Name' property for the managed resource compiler tool
	///          associated with all .resx files this class depends on.  Otherwise,
	///          the designers will not be able to interact properly with localized
	///          resources associated with this form.
	/// </summary>
	public ref class MainForm : public System::Windows::Forms::Form
	{
	public:
		MainForm(void)
		{
			InitializeComponent();

            // populate comboBox for Major Format selection
            majorFormatComboBox->DataSource = Enum::GetValues( SndFileMajorFormat::typeid );
            formatModifierComboBox->DataSource = Enum::GetValues( SndFileSubFormat::typeid );
            formatModifierComboBox->SelectedItem = SndFileSubFormat::PCM_16;

        }

	protected:
		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		~MainForm()
		{
			if (components)
			{
				delete components;
			}
		}
    private: System::Windows::Forms::Button^  startButton;
    private: System::Windows::Forms::TextBox^  logTextBox;
    private: System::Windows::Forms::TextBox^  srcTextBox;
    private: System::Windows::Forms::Label^  label1;
    private: System::Windows::Forms::ComboBox^  majorFormatComboBox;
    private: System::Windows::Forms::Label^  label2;
    private: System::Windows::Forms::ComboBox^  formatModifierComboBox;
    private: System::Windows::Forms::Label^  label3;
    private: System::Windows::Forms::TextBox^  dstTextBox;
    private: System::Windows::Forms::Label^  label4;
    private: System::Windows::Forms::OpenFileDialog^  openFileDialog;
    protected: 

	private:
		/// <summary>
		/// Required designer variable.
		/// </summary>
		System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		void InitializeComponent(void)
		{
            this->startButton = (gcnew System::Windows::Forms::Button());
            this->logTextBox = (gcnew System::Windows::Forms::TextBox());
            this->srcTextBox = (gcnew System::Windows::Forms::TextBox());
            this->label1 = (gcnew System::Windows::Forms::Label());
            this->majorFormatComboBox = (gcnew System::Windows::Forms::ComboBox());
            this->label2 = (gcnew System::Windows::Forms::Label());
            this->formatModifierComboBox = (gcnew System::Windows::Forms::ComboBox());
            this->label3 = (gcnew System::Windows::Forms::Label());
            this->dstTextBox = (gcnew System::Windows::Forms::TextBox());
            this->label4 = (gcnew System::Windows::Forms::Label());
            this->openFileDialog = (gcnew System::Windows::Forms::OpenFileDialog());
            this->SuspendLayout();
            // 
            // startButton
            // 
            this->startButton->Location = System::Drawing::Point(587, 475);
            this->startButton->Name = L"startButton";
            this->startButton->Size = System::Drawing::Size(75, 23);
            this->startButton->TabIndex = 0;
            this->startButton->Text = L"Convert";
            this->startButton->UseVisualStyleBackColor = true;
            this->startButton->Click += gcnew System::EventHandler(this, &MainForm::startButton_Click);
            // 
            // logTextBox
            // 
            this->logTextBox->Location = System::Drawing::Point(12, 316);
            this->logTextBox->Multiline = true;
            this->logTextBox->Name = L"logTextBox";
            this->logTextBox->Size = System::Drawing::Size(650, 137);
            this->logTextBox->TabIndex = 1;
            // 
            // srcTextBox
            // 
            this->srcTextBox->Location = System::Drawing::Point(12, 44);
            this->srcTextBox->Name = L"srcTextBox";
            this->srcTextBox->Size = System::Drawing::Size(650, 20);
            this->srcTextBox->TabIndex = 2;
            this->srcTextBox->Text = L"...";
            this->srcTextBox->DoubleClick += gcnew System::EventHandler(this, &MainForm::srcTextBox_DoubleClick);
            // 
            // label1
            // 
            this->label1->AutoSize = true;
            this->label1->Location = System::Drawing::Point(9, 28);
            this->label1->Name = L"label1";
            this->label1->Size = System::Drawing::Size(50, 13);
            this->label1->TabIndex = 3;
            this->label1->Text = L"Input File";
            // 
            // majorFormatComboBox
            // 
            this->majorFormatComboBox->FormattingEnabled = true;
            this->majorFormatComboBox->Location = System::Drawing::Point(12, 100);
            this->majorFormatComboBox->Name = L"majorFormatComboBox";
            this->majorFormatComboBox->Size = System::Drawing::Size(121, 21);
            this->majorFormatComboBox->TabIndex = 4;
            // 
            // label2
            // 
            this->label2->AutoSize = true;
            this->label2->Location = System::Drawing::Point(9, 84);
            this->label2->Name = L"label2";
            this->label2->Size = System::Drawing::Size(68, 13);
            this->label2->TabIndex = 5;
            this->label2->Text = L"Major Format";
            // 
            // formatModifierComboBox
            // 
            this->formatModifierComboBox->FormattingEnabled = true;
            this->formatModifierComboBox->Location = System::Drawing::Point(205, 99);
            this->formatModifierComboBox->Name = L"formatModifierComboBox";
            this->formatModifierComboBox->Size = System::Drawing::Size(121, 21);
            this->formatModifierComboBox->TabIndex = 6;
            // 
            // label3
            // 
            this->label3->AutoSize = true;
            this->label3->Location = System::Drawing::Point(202, 83);
            this->label3->Name = L"label3";
            this->label3->Size = System::Drawing::Size(61, 13);
            this->label3->TabIndex = 5;
            this->label3->Text = L"Sub Format";
            // 
            // dstTextBox
            // 
            this->dstTextBox->Location = System::Drawing::Point(12, 161);
            this->dstTextBox->Name = L"dstTextBox";
            this->dstTextBox->Size = System::Drawing::Size(650, 20);
            this->dstTextBox->TabIndex = 2;
            // 
            // label4
            // 
            this->label4->AutoSize = true;
            this->label4->Location = System::Drawing::Point(9, 145);
            this->label4->Name = L"label4";
            this->label4->Size = System::Drawing::Size(58, 13);
            this->label4->TabIndex = 3;
            this->label4->Text = L"Output File";
            // 
            // MainForm
            // 
            this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
            this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
            this->ClientSize = System::Drawing::Size(674, 510);
            this->Controls->Add(this->formatModifierComboBox);
            this->Controls->Add(this->label3);
            this->Controls->Add(this->label2);
            this->Controls->Add(this->majorFormatComboBox);
            this->Controls->Add(this->label4);
            this->Controls->Add(this->label1);
            this->Controls->Add(this->dstTextBox);
            this->Controls->Add(this->srcTextBox);
            this->Controls->Add(this->logTextBox);
            this->Controls->Add(this->startButton);
            this->Name = L"MainForm";
            this->Text = L"SndFileConverter with LibSndFile";
            this->ResumeLayout(false);
            this->PerformLayout();

        }
#pragma endregion
    private: System::Void startButton_Click(System::Object^  sender, System::EventArgs^  e) {
                 String^ srcPath = srcTextBox->Text;
                 IO::FileStream^ srcFileStream = gcnew IO::FileStream( srcPath, IO::FileMode::Open, IO::FileAccess::Read );
                 SndFileInfo srcSndFileInfo;
                 SndFile^ srcSndFile;
                 String^ dstPath = dstTextBox->Text;
                 IO::FileStream^ dstFileStream = gcnew IO::FileStream( dstPath, IO::FileMode::Create, IO::FileAccess::Write/*, IO::FileShare::Write*/ );
                 SndFileInfo dstSndFileInfo;
                 SndFile^ dstSndFile;
                 bool continueNormalExecution = true;
                 

                 try
                 {
                    srcSndFile = gcnew SndFile( srcFileStream, %srcSndFileInfo );
                 }
                 catch( Exception^ )
                 {
                     logTextBox->Text = "ERROR: Unable to open the sound file" + Environment::NewLine;
                     continueNormalExecution = false;
                 }

                 if( continueNormalExecution )
                 {
                     logTextBox->Text += "Source file stream opening: " + srcPath + Environment::NewLine;
                     logTextBox->Text += "\tSamplesPerSecond: " + srcSndFileInfo.SamplesPerSecond + Environment::NewLine;
                     logTextBox->Text += "\tChannels: " + srcSndFileInfo.Channels + Environment::NewLine;
                     logTextBox->Text += "\tFormat: 0x" + Convert::ToString(srcSndFileInfo.Format, 16) + Environment::NewLine;

                     dstSndFileInfo.SamplesPerSecond = srcSndFileInfo.SamplesPerSecond;
                     dstSndFileInfo.Channels = srcSndFileInfo.Channels;
                     dstSndFileInfo.Format = ( (int) majorFormatComboBox->SelectedItem | (int) formatModifierComboBox->SelectedItem );                 
                 }

                 try
                 {
                     if( continueNormalExecution )
                         dstSndFile = gcnew SndFile( dstFileStream, %dstSndFileInfo );
                 }
                 catch( Exception^ )
                 {
                     logTextBox->Text = "ERROR: Unable to create the sound file" + Environment::NewLine;
                     continueNormalExecution = false;
                 }

                 if( continueNormalExecution )
                 {
                     logTextBox->Text += "Destination file stream creation: " + dstPath + Environment::NewLine;
                     logTextBox->Text += "\tSamplesPerSecond: " + dstSndFileInfo.SamplesPerSecond + Environment::NewLine;
                     logTextBox->Text += "\tChannels: " + dstSndFileInfo.Channels + Environment::NewLine;
                     logTextBox->Text += "\tFormat: 0x" + Convert::ToString(dstSndFileInfo.Format, 16) + Environment::NewLine;

                     array<short>^ buffer = gcnew array<short>(512);
                     // reading source sound file until the end

                     long long countOfItemsWritten;
                     long long countOfItemsRead;
                     while ( (countOfItemsRead = srcSndFile->Read( buffer, buffer->Length )) > 0 )
                     {
                         countOfItemsWritten = dstSndFile->Write( buffer, countOfItemsRead );

                         if( countOfItemsWritten != countOfItemsWritten )
                             throw gcnew IO::IOException( "IO error when writing data to the destination sound file" );
                     }
                 }                

                 if( dstSndFile != nullptr )
                    delete dstSndFile;
                 if( srcSndFile != nullptr )
                    delete srcSndFile;
                 srcFileStream->Close();
                 dstFileStream->Close();
             }

private: System::Void srcTextBox_DoubleClick(System::Object^  sender, System::EventArgs^  e) {
                 Windows::Forms::DialogResult result = openFileDialog->ShowDialog();

                 if( result == Windows::Forms::DialogResult::OK )
                 {
                     srcTextBox->Text = openFileDialog->FileName;
                 }
         }
};
}

